﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Text.RegularExpressions;
using eXamineBusiness.System.Exceptions;

namespace eXamineBusiness.SystemDescription.Data
{
    public class NameCollection
    {
        [Pure]
        public static bool ValidName (String name)
        {
            Contract.Requires(name != null);
            return NameCollection.NamePatternExpression.Match(name).Success;
        }

        private static readonly Regex NamePatternExpression = new Regex("^_?[a-zA-Z_][a-zA-Z0-9_]*$");
        private readonly Dictionary<String, DescriptionItem> _names;

        public NameCollection ()
        {
            this._names = new Dictionary<String, DescriptionItem>();
        }
        [ContractInvariantMethod]
        private void ThisCanHaveAnyNameYouWant()
        {
            Contract.Invariant(this._names != null);
            Contract.Invariant(this._names.Count >= 0);
            // Unicidade das chaves é garantida pelo dicionario
        }

        [Pure]
        public bool Exists (String name)
        {
            if (name == null) return false;
            return this._names.ContainsKey(name);
        }

        public void Add(String name, DescriptionItem obj)
        {
            Contract.Requires(name != null);
            Contract.Requires(obj != null);
            Contract.Requires<InvalidNameException>(ValidName(name), "name");
            Contract.Requires<ArgumentException>(!Exists(name));
            Contract.Ensures(_names.ContainsKey(name));
            Contract.Ensures(_names[name].Equals(obj));
            if (!NameCollection.ValidName(name)) 
                throw new InvalidNameException();
            this._names.Add(name, obj);
            obj.ItemRemoved += new EventHandler(obj_ItemRemoved);
        }

        private void obj_ItemRemoved(object sender, EventArgs e)
        {
            if (sender != null &&  sender is DescriptionItem)
            {
                this.Remove(((DescriptionItem)sender).Name);
            }
        }

        public void Remove (String name)
        {
            Contract.Requires(name != null);
            Contract.Requires(Exists(name));
            Contract.Ensures(!Exists(name));
            this._names.Remove(name);
        }


        public void Rename (String from, String to)
        {
            Contract.Requires(to != null);
            Contract.Requires(from != null);
            Contract.Requires<NameAlreadyExistsException>(ValidName(to));
            Contract.Ensures(this[to].Equals(Contract.OldValue(this)[from]));
            Contract.Ensures(!Exists(from));
            if (this._names.Count > 0) { 
                if (this.Exists(to)) throw new NameAlreadyExistsException();
                else
                {
                    DescriptionItem obj = this._names[from];
                    this.Add(to, obj);
                    this.Remove(from);
                }
            }
        }

        [Pure]
        public DescriptionItem this[String name]
        {
            get
            {
                if (this.Exists(name))
                    return this._names[name];
                else
                    return null;
            }
        }

    }
}
